package CH8;

//前置知识：
//1)从DK1.7开始，JVM就将常量池从方法区中移到堆中，但跟普通的变量对象不在一起，是一个专门的区域；
//2)从JDK源码知，String底层由字节数组value实现，且其被final修饰，故而String是一个不可变对象，因此它可共享；
//3)通过new方式产生的String对象，如【String str1=new String("ab");】,在堆里（非常量池）构建，不可共享；
//4)直接用常量构建出来的字符串对象，如【String str1="ab";】被分配在常量池中（非普通堆区），编译器会对其进行优化，
//  会记录在一个表中,即当一个字符串已经存在时，不再重复创建一个相同的对象，而是直接共享；
//5)当final变量修饰基本数据类型以及String类型时，编译期间能知道它的确切值时，编译器会把它当做编译期常量使用。
//也就是说在用到该final变量的地方，相当于直接访问的这个常量，不需要在运行时确定。类似C语言的宏替换。
public class FinalAndVariableDifference {

    public static void main(String[] args) {
//完成了3件事：1）堆里构建一个byte[97,98]数组，以存储【ab】的ASCII码值,假设其地址值为【0x11】；
//2)在常量池里构建了一个String对象，假设其地址值为【0x22】,随后将【0x11】赋值给了此对象的value属性（即value指向数组[97,98]）；
//3）在栈里开辟一个变量区（str1），并给其赋值为【0x22】（即str1指向常量池里的String对象）
        String s1 = "ab";//s1所指对象在常量池里
//完成了1件事：在栈里开辟一个变量区（str2），并给其赋值为【0x22】（即str2也指向常量池里的String对象）
        String s2 = "ab";//将s2也指向"ab"
        System.out.println("s1.equals(s2)="+(s1.equals(s2)));//equals比较的是内容，内容一样，结果自然是：true
        System.out.println("s1==s2="+(s1==s2));//==比较的是地址，由于都指向同一个对象，故结果是：true

//new出来的对象分配在heap中，不可共享，故s3与s4虽然它们指向的字符串内容是相同的，但是是两个不同的对象.
//完成3件事：1）在堆里构建一个byte[97,98]数组，以存储【ab】的ASCII码值,假设其地址值为【0x33】；
//2)在堆里构建了一个String对象，假设其地址值为【0x44】,随后将【0x33】赋值给了此对象的value属性（即value指向数组[97,98]）；
//3）在栈里开辟一个变量区（str3），并给其赋值为【0x44】（即str3指向堆里的String对象）
        String s3 = new String("ab");
//完成3件事：1）在堆里构建一个byte[97,98]数组，以存储【ab】的ASCII码值,假设其地址值为【0x55】；
//2)在堆里构建了一个String对象，假设其地址值为【0x66】,随后将【0x55】赋值给了此对象的value属性（即value指向数组[97,98]）；
//3）在栈里开辟一个变量区（str4），并给其赋值为【0x66】（即str4指向堆里的String对象）
        String s4 = new String("ab");
        System.out.println("s3.equals(s4)="+(s3.equals(s4)));//equals比较的是内容，内容一样，结果自然是：true
        System.out.println("s3==s4="+(s3==s4));   //==比较的是地址，由于都指向不同的对象，故结果是：false

// String中equals方法已经被重写过，比较的是内容是否相等
        String s5 = "ab1";
        final String s6 = "ab";//编译时初始化，编译器会优化
        final String s7 = getString();//运行时初始化，编译器无法优化

        String s8 = s1 + 1;//s1是变量，其值="ab"，变量时编译器无法优化
        String s9 = s6 + 1;//s6是final变量且是编译时初始化
        String s10 = s7 + 1;//s6是final变量且是编译时初始化
        System.out.println("s8==s5="+(s8==s5));//不同的对象，结果自然是：false
        System.out.println(("s9==s5="+(s9==s5)));//编译时初始化，编译器优化，会共享已有对象，结果自然是：true
        System.out.println(("s10==s5="+(s10==s5)));//运行时初始化，编译器无法优化，结果自然是：false
    }
    public static String getString() {
        return "ab";
    }
}
